package nave.model;

import nave.Constants;
import nave.Point;

public abstract class Spaceship extends GameObject {

	/*
	 * Constants
	 */
	public static final int STATUS_NORMAL = 0;
	public final static int STATUS_INVENCIBLE = 1;

	public final static int DIRECTION_UP = -1;
	public final static int DIRECTION_DOWN = 1;
	public final static int DIRECTION_LEFT = -2;
	public final static int DIRECTION_RIGHT = 2;

	/*
	 * Attributes	
	 */
	protected Point deltaMove;
	private int speed;
	private int status = STATUS_NORMAL;
	private int direction = DIRECTION_RIGHT;
	protected int nextDirection;
	private int numberOfBullets;
	private int bulletsFired;
	public boolean isExploding;
	private float explodeTime;

	/*
	 * Constructors
	 */
	public Spaceship(int id, int numberOfBullets) {

		super(id);

		deltaMove = new Point(0, 0);

		setSpeed(Constants.DEFAULT_SPEED);
		isExploding = false;
		explodeTime = 0;

		this.numberOfBullets = numberOfBullets;
		this.bulletsFired = 0;

		drawPoint = new Point(position.x * Constants.TILE_WIDTH,
				position.y * Constants.TILE_HEIGHT);
	}

	/*
	 *  Getters and Setters
	 */
	public int getSpeed() {
		return speed;
	}
	public void setSpeed(int speed) {
		this.speed = speed;
	}

	public int getStatus() {
		return status;
	}
	public void setStatus(int status) {
		this.status = status;
	}

	public int getDirection() {
		return direction;
	}
	public void setDirection(int direction) {
		this.nextDirection = direction;
	}
	
	public void increaseNumberOfBullets() {
		if ( numberOfBullets < Constants.BULLETS_LIMIT )
			numberOfBullets++;
	}
	public void decreaseNumberOfBullets() {
		if ( numberOfBullets > 1 )
			numberOfBullets--;
	}
	public void decreaseBulletsFired() {
		bulletsFired--;
	}

	/*
	 * Public methods
	 */
	@Override
	public void update(float delta) {
		// TODO work with the delta!!!

		if (isExploding) {
			explodeTime += delta;
			if (explodeTime > Explosion.EXPLOSION_TIME) {
				isExploding = false;
				explodeTime = 0;
			}
			return;
		}

		// moves
		drawPoint.translate(deltaMove.x*speed, deltaMove.y*speed);

		// if ready, moves to the next direction
		// TODO what about speed changing?
		if ( (drawPoint.x % Constants.TILE_WIDTH == 0 &&
				drawPoint.y % Constants.TILE_HEIGHT == 0) ||
				( nextDirection == -direction ) )	// this is to reverse the direction
		{
			finishMove();
			move(nextDirection);
		}
		
		extra();
	} 

	public Shot shot() {
		if ( bulletsFired < numberOfBullets && !this.isExploding )
		{
			bulletsFired++;
			return new Shot(direction, this);
		}
		else
			return null;
	}

	public abstract void explode();

	/*
	 * Private methods
	 */
	private void move( int direction ) {

		int deltaY = 0,
			deltaX = 0;

		switch( direction )
		{
			case DIRECTION_UP:
			{
				deltaY = -1;
				break;
			}
			case DIRECTION_DOWN:
			{
				deltaY = 1;
				break;
			}
			case DIRECTION_LEFT:
			{
				deltaX = -1;
				break;
			}
			case DIRECTION_RIGHT:
			{
				deltaX = 1;
				break;
			}
			default: return;
		}
		this.direction = direction;

		// TODO change so you can get items
		if ( Stage.getPositionOnStage(position.y+deltaY, position.x+deltaX) == Constants.EMPTY )
		{
			// fills the matrix next position
			deltaMove.setLocation(deltaX, deltaY);
			position.translate(deltaMove);
			Stage.setPositionOnStage(position, id);
		}
		else
		{
			cancelMove();
		}
	}
	protected void finishMove() {
		// clear the previously occupied position on the matrix
		if ( ! deltaMove.equals(new Point(0, 0)) )
			Stage.setPositionOnStage( position.y-deltaMove.y,
					position.x-deltaMove.x, Constants.EMPTY );
	}
	private void cancelMove() {
		deltaMove.setLocation(0, 0);
		nextDirection = 0;
	}
	
	/* Extra function for the update */
	protected abstract void extra();

}
